﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

using ESRI.ArcGIS.Client.Geometry;

using TouchToolkit.Framework;
using TouchToolkit.GestureProcessor.ReturnTypes;
using TouchToolkit.Framework.TouchInputProviders;
using TouchToolkit.GestureProcessor.Feedbacks.TouchFeedbacks;
using TouchToolkit.GestureProcessor.Gesture_Definitions;

using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;


namespace eGrid_App
{
    /// <summary>
    /// The layer that holds MapFrames, GhostFrames, and BookmarkListFrames.
    /// This class contains functions that allows
    /// the creation and deletion of the above objects.
    /// </summary>
    public partial class ScatterLayer : UserControl
    {
        #region members and containers

        private List<Bookmark> bookmarks;

        // List of the MapFrames which are placed on the layer
        private List<MapFrame> mapFramesList;
        // List of the ghost frames which are placed on the layer
        private List<GhostFrame> ghostFramesList;
        // List of Bookmark list frames which are placed on the layer
        private List<BookmarkListFrame> bookmarkListFramesList;

        private MapLayersMangerPanel _mapLayersManagerPanel;

        double _width, _height;

        #endregion

        #region Constructor and initialization

        public ScatterLayer(TouchInputProvider provider, double width, double height)
        {
            
            InitializeComponent(); 

            /* Adding the Map Layers Manager Panel in hidden mode */
            _mapLayersManagerPanel = new MapLayersMangerPanel();
            _mapLayersManagerPanel.Orientation = 270.0;
            _mapLayersManagerPanel.Center = new Point(400, 400);
            _mapLayersManagerPanel.Visibility = Visibility.Hidden;
            BackgroundScatterView.Items.Add(_mapLayersManagerPanel);

            /* Must invert width and height since the background map is turned 90 deg */
            ScatterCanvas.Height = width;
            ScatterCanvas.Width = height;

            BackgroundScatterView.Width = height;
            BackgroundScatterView.Height = width;

            _width = width;
            _height = height;

			CreateBookmarkList();

            InitializeBackgroundMap();

            // initialize the lists
            mapFramesList = new List<MapFrame>();
            ghostFramesList = new List<GhostFrame>();
            bookmarkListFramesList = new List<BookmarkListFrame>();

            GestureFramework.EventManager.AddEvent(ScatterCanvas, Gestures.Lasso, ScatterLayer_Lasso);
        }
                
        private void InitializeBackgroundMap()
        {
            BackgroundMap.MyMap.Layers = MapLayersManager.Instance.MapLayers;
            
            // Disabling manipulation on the main map stops it from handling touches, so that they are promoted to mouse clicks
            BackgroundMap.isMainMap = true;

            /* Associate the background map with this ScatterLayer as its parent */
            BackgroundMap.ParentScatterLayer = this;

            /* make map full screen */
            BackgroundMap.Height = _width;
            BackgroundMap.Width = _height;

            /* Setting the background of the screen to the map of Calgary */
            BackgroundMap.setExtentFromEnvelop(new Envelope(-114.25, 51.00, -113.88, 51.05));
            

        }

        /// <summary>
        /// Handles the event when the background map is loaded.
        /// When the background map is loaded, functions that
        /// rely on the final position of the background map relative
        /// to the screen can be called.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected void BackgroundMap_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void CreateBookmarkList()
        {
            bookmarks = new List<Bookmark>();

            Envelope mEnv1 = new Envelope(-114.165225251302, 51.0199795790397, -114.149512923988, 51.0355755135701);
            Bookmark tt1 = new Bookmark(mEnv1, "Out of order lights", "0006780", Bookmark.BookmarkPriority.High);
            bookmarks.Add(tt1);

            Envelope mEnv2 = new Envelope(-114.146822616181, 51.1247138317455, -114.12585847052, 51.1364297207226);
            Bookmark tt2 = new Bookmark(mEnv2, "Repair Transformer", "0006889", Bookmark.BookmarkPriority.Medium);
            bookmarks.Add(tt2);

            Envelope mEnv3 = new Envelope(-114.05252218858, 51.1188308476309, -114.031558073198, 51.130546736608);
            Bookmark tt3 = new Bookmark(mEnv3, "Svc Request", "0009189", Bookmark.BookmarkPriority.Low);
            bookmarks.Add(tt3);

            Envelope mEnv4 = new Envelope(-114.105225251302, 51.0199795790397, -114.109512923988, 51.0355755135701);
            Bookmark tt4 = new Bookmark(mEnv4, "Power outage", "0003781", Bookmark.BookmarkPriority.High);
            bookmarks.Add(tt4);

            Envelope mEnv5 = new Envelope(-113.991064469202, 51.0490752572698, -113.970100323542, 51.0607911462469);
            Bookmark tt5 = new Bookmark(mEnv5, "New transformer Z12", "0002380", Bookmark.BookmarkPriority.Medium);
            bookmarks.Add(tt5);

            Envelope mEnv6 = new Envelope(-114.099545255042, 51.0710092027607, -114.0785811092382, 51.0827250917378);
            Bookmark tt6 = new Bookmark(mEnv6, "Power outage", "0007641", Bookmark.BookmarkPriority.Low);
            bookmarks.Add(tt6);

            Envelope mEnv7 = new Envelope(-114.080433237526, 50.913367183679, -114.059469091866, 50.92508307656);
            Bookmark tt7 = new Bookmark(mEnv7, "Wire installation", "0002341", Bookmark.BookmarkPriority.High);
            bookmarks.Add(tt7);
        }
        
        public List<Bookmark> getBookmarks()
        {
            return bookmarks;
        }


        #endregion

        #region Creating Detailed Map Windows (via 2-point touch)

        private void ScatterLayer_Lasso(UIElement sender, GestureEventArgs e)
        {

            TouchPoints pts = e.Values.Get<TouchPoints>();

            int middlePt = (int)Math.Floor((decimal)(pts.Count / 2));
            Point scrPoint1 = new Point(pts[0].Y, BackgroundScatterView.Height - pts[0].X);
            Point scrPoint2 = new Point(pts[middlePt].Y, BackgroundScatterView.Height - pts[middlePt].X);

            MapPoint mapPoint1 = BackgroundMap.Map.ScreenToMap(scrPoint1);
            MapPoint mapPoint2 = BackgroundMap.Map.ScreenToMap(scrPoint2);

            Point point1 = BackgroundMap.Map.MapToScreen(mapPoint1);
            Point point2 = BackgroundMap.Map.MapToScreen(mapPoint2);

            CreateMapFrameFromMapPoints(mapPoint1, mapPoint2, scrPoint1, scrPoint2);
        }

        #endregion
        
        #region Adding and removing scatterItems

        /// <summary>
        /// Randomly generates a colour for a new
        /// MapFrame
        /// </summary>
        /// <returns></returns>
        private SolidColorBrush GetRandomColor()
        {
            /* 
             * Randomly generate a color
             * 
             * byte r = represents the red byte
             * byte g = the green byte
             * byte b = blue byte
             */
            Random rnd = new Random();
            byte r = Convert.ToByte(rnd.Next(0, 192));
            byte g = Convert.ToByte(rnd.Next(0, 192));
            byte b = Convert.ToByte(rnd.Next(0, 192));
            return new SolidColorBrush(Color.FromRgb(r, g, b));
        }

        /// <summary>
        /// Search for the MapFrame in this layer that is related to the
        /// given Bookmark.  If the MapFrame exists, return it, otherwise, return
        /// null.
        /// </summary>
        /// <param name="bookmark"></param>
        /// <returns></returns>
        public MapFrame GetMapFrame(Bookmark bookmark)
        {
            for (int i = 0; i < mapFramesList.Count; i++)
            {
                if (mapFramesList[i] is MapFrame)
                {
                    MapFrame mp = mapFramesList[i] as MapFrame;
                    if (mp.RelatedBookmark == bookmark)
                        return mp;
                }
            }
            return null;
        }

        /// <summary>
        /// Removes a MapFrame, if it already exists
        /// </summary>
        /// <param name="deleteMap"></param>
        public void RemoveMap(MapFrame deleteMap)
        {
            GhostFrame gf = deleteMap.GetGhostFrame();

            if (mapFramesList.Contains(deleteMap))
            {
                mapFramesList.Remove(deleteMap);
                ghostFramesList.Remove(gf);
            }

            if (BackgroundScatterView.Items.Contains(deleteMap))
                BackgroundScatterView.Items.Remove(deleteMap);
            if (BackgroundScatterView.Items.Contains(gf))
                BackgroundScatterView.Items.Remove(gf);
        }

        /// <summary>
        /// Removes a BookmarkListFrame, if it
        /// already exists on the layer.
        /// </summary>
        /// <param name="deleteFrame"></param>
        public void RemoveBookmarkListFrame(BookmarkListFrame deleteFrame)
        {
            if (bookmarkListFramesList.Contains(deleteFrame))
                bookmarkListFramesList.Remove(deleteFrame);
            if (BackgroundScatterView.Items.Contains(deleteFrame))
                BackgroundScatterView.Items.Remove(deleteFrame);
        }

        public void HideMapLayersManagerPanel()
        {
            _mapLayersManagerPanel.Visibility = Visibility.Hidden;
        }

        public void AddMapTip(BookmarkInfoTip mapTip, Point screen_point, double orientation)
        {
            mapTip.Orientation = orientation;
            mapTip.Center = screen_point;

            BackgroundScatterView.Items.Add(mapTip);    
        }


        public void AddFeatureTip(FeatureInfoTip featureTip, Point screen_point, double orientation)
        {
            featureTip.Orientation = orientation;
            featureTip.Center = screen_point;

            BackgroundScatterView.Items.Add(featureTip);
        }

        public void RemoveFeatureTip(FeatureInfoTip featureTip)
        {
            BackgroundScatterView.Items.Remove(featureTip);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="orientation"></param>
        public BookmarkListFrame AddBookmarkListFrame(Point pt, double orientation)
        {
            BookmarkListFrame ttlFrame = new BookmarkListFrame(this, pt, orientation);
            bookmarkListFramesList.Add(ttlFrame);

            BackgroundScatterView.Items.Add(ttlFrame);

            return ttlFrame;
        }

        /// <summary>
        /// This method will handle the functionality
        /// when the "Search" button is clicked.
        /// </summary>
        /// <param name="loc"></param>
        public void AddSearchBox(Point loc)
        {
            //ScatterViewItem container = new ScatterViewItem();
            //SurfaceKeyboard.CenterX = (float)loc.X;
            //SurfaceKeyboard.CenterY = (float)loc.Y;
            //SurfaceKeyboard.IsVisible = true;
            //AddMapAnnotation(loc);

        }

        public void ShowConfigPanel(Point pt, double orientation)
        {
            _mapLayersManagerPanel.Center = pt;
            _mapLayersManagerPanel.Orientation = orientation;
            _mapLayersManagerPanel.Visibility = Visibility.Visible;
        }

        #endregion

        #region Creating Map Frames
        /// <summary>
        /// Adds a new MapFrame to the layer via the
        /// two map points from the map.
        /// 
        /// A MapFrame is created where the extent are defined
        /// by the two points (one for upper left corner and the
        /// other for lower right corner).
        /// 
        /// The position of the MapFrame on the screen is also defined
        /// by the 2 Points value (one for upper left corner and another
        /// for lower right corner).
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        public void CreateMapFrameFromMapPoints(MapPoint p1, MapPoint p2, Point point1, Point point2)
        {
            SolidColorBrush randomColor = GetRandomColor();

            GhostFrame gFrame = new GhostFrame(BackgroundMap, new Envelope(p1, p2), randomColor);
            MapFrame mFrame = new MapFrame(this, gFrame, p1, p2, randomColor);

 

            mFrame.Orientation = 0.0;

            var xDiff = Math.Abs(point1.X - point2.X);
            var yDiff = Math.Abs(point1.Y - point2.Y);

            if (point1.X < point2.X && point1.Y < point2.Y)
            {
                mFrame.Orientation = 0.0;
                mFrame.Height = yDiff;
                mFrame.Width = xDiff;
                mFrame.Center = new System.Windows.Point(point1.X + xDiff / 2, point1.Y + yDiff / 2);
            }
            else if (point1.X > point2.X && point1.Y < point2.Y)
            {
                mFrame.Orientation = 90.0;
                mFrame.Height = yDiff;
                mFrame.Width = xDiff;
                mFrame.Center = new System.Windows.Point(point1.X - xDiff / 2, point1.Y + yDiff / 2);
            }
            else if (point1.X > point2.X && point1.Y > point2.Y)
            {
                mFrame.Orientation = 180.0;
                mFrame.Height = yDiff;
                mFrame.Width = xDiff;
                mFrame.Center = new System.Windows.Point(point1.X - xDiff / 2, point1.Y - yDiff / 2);
            }
            else if (point1.X < point2.X && point1.Y > point2.Y)
            {
                mFrame.Orientation = 270.0;
                mFrame.Height = yDiff;
                mFrame.Width = xDiff;
                mFrame.Center = new System.Windows.Point(point1.X + xDiff / 2, point1.Y - yDiff / 2);
            }

            
           
            gFrame.Orientation = mFrame.Orientation;
            gFrame.Height = mFrame.Height;
            gFrame.Width = mFrame.Width;
            gFrame.Center = mFrame.Center;

            ghostFramesList.Add(gFrame);
            mapFramesList.Add(mFrame);

            BackgroundScatterView.Items.Add(gFrame);
            BackgroundScatterView.Items.Add(mFrame);
        }

        /// <summary>
        /// Adds a new MapFrame to the layer via the
        /// BookmarkPins.
        /// 
        /// The position of the MapFrame (centre) is the
        /// same as the related BookmarkPin.  The 
        /// orientation of the frame is also defined. The
        /// map extent of the frame is the same as the
        /// related Bookmark.
        /// </summary>
        /// <param name="bookmark"></param>
        /// <param name="centerPt"></param>
        /// <param name="orientation"></param>
        public void CreateMapFrameFromBookmarkPin(Bookmark bookmark, Point centerPt, double orientation)
        {
            /* if it is already open, dont open again */
            if (bookmark.MapFrameCurrentlyOpen == true)
            {
                // bring to front
                GetMapFrame(bookmark).ZIndex = 10;
                return;
            }

            Envelope mapExtent = new Envelope();
            double frameHeight = 270;
            double frameWidth = 270;
            Point frameCenter = centerPt;
            double frameOri = orientation;

            if (bookmark.MapFramePreviouslyOpen == true)
            {
                /* Do we really want to open the map frame from its previous position? */
                //mapExtent = bookmark.MapFrameEnvelope;
                //frameHeight = bookmark.MapFrameHeight;
                //frameWidth = bookmark.MapFrameWidth;
                //frameCenter = bookmark.MapFrameCenter;
                //frameOri = bookmark.MapFrameOrientation;
            }
            else
            {
                mapExtent = bookmark.MapFrameEnvelope;
                //frameHeight = height;
                //frameWidth = width;
                frameCenter = centerPt;
            }

            SolidColorBrush randomColor = GetRandomColor();
            GhostFrame gFrame = new GhostFrame(BackgroundMap, mapExtent, randomColor);
            MapFrame mFrame = new MapFrame(this, gFrame, mapExtent, randomColor);


            mFrame.RelatedBookmark = bookmark;
            mFrame.Orientation = frameOri;
            mFrame.Height = frameHeight;
            mFrame.Width = frameWidth;
            mFrame.Center = frameCenter;

            bookmark.MapFrameCurrentlyOpen = true;

            ghostFramesList.Add(gFrame);
            mapFramesList.Add(mFrame);

            BackgroundScatterView.Items.Add(gFrame);
            BackgroundScatterView.Items.Add(mFrame);
        }

        /// <summary>
        /// This is called when user clicks on a Bookmark from
        /// the BookmarkListFrame.  A MapFrame is created that
        /// represents the Bookmark that was selected.
        /// </summary>
        /// <param name="bookmark"></param>
        /// <param name="centerPt"></param>
        /// <param name="orientation"></param>
        public void CreateMapFrameFromBookmarkList(Bookmark bookmark, Point centerPt, double orientation)
        {
            /* if it is already open, dont open again */
            if (bookmark.MapFrameCurrentlyOpen == true)
            {
                // bring to front
                MapFrame mp = GetMapFrame(bookmark);
                mp.IsEnabled = true; // was IsContainerActive
                return;
            }

            Envelope mapExtent = bookmark.MapFrameEnvelope;
            double frameHeight = 270;
            double frameWidth = 270;
            double frameOri = orientation + 90;

            SolidColorBrush randomColor = GetRandomColor();
            GhostFrame gFrame = new GhostFrame(BackgroundMap, mapExtent, randomColor);
            MapFrame mFrame = new MapFrame(this, gFrame, mapExtent, randomColor);



            mFrame.RelatedBookmark = bookmark;
            mFrame.Orientation = frameOri;
            mFrame.Height = frameHeight;
            mFrame.Width = frameWidth;
            mFrame.Center = centerPt;

            bookmark.MapFrameCurrentlyOpen = true;

            ghostFramesList.Add(gFrame);
            mapFramesList.Add(mFrame);

            BackgroundScatterView.Items.Add(gFrame);
            BackgroundScatterView.Items.Add(mFrame);
        }

        #endregion

        //private void ScatterCanvas_TouchDown(object sender, TouchEventArgs e)
        //{
        //    TouchPoint point = e.GetTouchPoint(ScatterCanvas);
            
        //    ScatterViewItem svi = new ScatterViewItem();
        //    svi.Center = point.Position;
        //    ScatterCanvas.Children.Add(svi);
        //}

        //private void ScatterCanvas_TouchMove(object sender, TouchEventArgs e)
        //{

        //}

        //private void ScatterCanvas_TouchUp(object sender, TouchEventArgs e)


    }
}
